<?php

require_once('classes/IRequestHandler.php');
require_once('classes/IResponseHandler.php');
require_once('classes/JsonRequestHandler.php');
require_once('classes/JsonResponseHandler.php');
require_once('classes/NoSuchMethodException.php');

abstract class WebService {
	
	protected $requestHandler;
	protected $responseHandler;
	
	public function __construct(IRequestHandler $requestHandler = null, IResponseHandler $responseHandler = null) {
		// create default handler if one not provided
		if ($requestHandler == null) {
			$requestHandler = new JsonRequestHandler();	
		}
		
		// create default handler if one not provided
		if ($responseHandler == null) {
			$responseHandler = new JsonResponseHandler();
		}
		
		$this->requestHandler = $requestHandler;
		$this->responseHandler = $responseHandler;
	}
	
	public function getRequest() {
		return $this->requestHandler->getRequest();
	}
	
	public function getRawRequest() {
		return $this->requestHandler->getRawRequest();
	}
	
	public function getRequestHandler() {
		return $this->requestHandler;
	}
	
	public function setRequestHandler(IRequestHandler $handler) {
		$this->requestHandler = $handler;
	}
	
	public function getResponseHandler() {
		return $this->responseHandler;
	}
	
	public function setResponseHandler(IResponseHandler $handler) {
		$this->responseHandler = $handler;
	}
	
	public function getRequestedMethod() {
		if (isset($_GET['mn'])) {
			return $_GET['mn'];
		}
		
		return null;
	}
	
	protected final function invoke($name, $request) {
		$r = new ReflectionClass($this); 
 
 		// attempt to invoke the requested method
		if ($method = $r->getMethod($name)) {
			if ($method->isPublic() && !$method->isAbstract()) {
				return $method->invoke($this, $request);
			}
		}
		
		// method requested doesn't exist
		throw new NoSuchMethodException($r->getName(), $name);	
	}
	
	protected function send($response = null) {
		$this->requestHandler->flush();
		$this->responseHandler->setResponse($response);
		$this->responseHandler->handle();
	}
	
	public function listen() {
		$this->requestHandler->flush();
		$this->requestHandler->handle();
		$this->invoke($this->getRequestedMethod(), $this->getRequest());
	}
	
} 